package multi_thread.master.tools;

import multi_thread.master.executors.Executor_CachedThreadPool;

import java.util.concurrent.*;

/**
 * @author Cheng Jun
 * Description: 阶段器（移相器），把一个事情分成多个阶段，每个阶段都可以新增 参与者 或 减少参与者，比 CyclicBarrier 更灵活。
 * 下面例子 模拟了 婚礼场景：分四个阶段
 * 第 0 阶段 父母双方和新郎、新娘 到场；
 * 第 1 阶段 父母双方和新郎、新娘 + 另外2个朋友 吃饭；
 * 第 2 阶段 父母双方和新郎、新娘 离席；
 * 第 3 阶段 新郎、新娘 洞房
 *
 * 更多用法，请学习 Phaser多任务协同的神器 - 消失er的文章
 * https://zhuanlan.zhihu.com/p/151327554
 *
 * @version 1.0
 * @date 2020/3/7 11:22
 * @see Phaser
 * @see Executor_CachedThreadPool
 */
public class PhaserExample {

    public static void main(String[] args) {
        ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
        MarriagePhaser marriagePhaser = new MarriagePhaser();
        // 默认参加婚礼的人，新郎和新娘
        marriagePhaser.bulkRegister(2);
        // 双方父母
        for (int i = 0; i < 4; i++) {
            Person person = new Person("parents " + (i + 1), marriagePhaser);
            Runnable task = () -> {
                marriagePhaser.register();
                person.arrive();
                person.eat();
                person.leave();
                marriagePhaser.arriveAndDeregister();
            };
            cachedThreadPool.execute(task);
        }

        // 朋友参与婚礼 吃饭时候加入
        for (int i = 0; i < 2; i++) {
            Person person = new Person("friends " + (i + 1), marriagePhaser);
            Runnable task = () -> {
                while (!marriagePhaser.isTerminated()) {
                    if (marriagePhaser.getPhase() == 1) {
                        marriagePhaser.register();
                        person.eat();
                        // person.leave();
                        // 退出阶段器，退出婚礼
                        System.out.println(person.name + " 退出婚宴");
                        marriagePhaser.arriveAndDeregister();
                    }
                }
            };
            cachedThreadPool.execute(task);
        }

        Person bridegroom = new Person("新郎", marriagePhaser);
        Person bride = new Person("新娘", marriagePhaser);
        Runnable bridegroomTask = () -> {
            bridegroom.arrive();
            bridegroom.eat();
            bridegroom.leave();
            bridegroom.sleep();
        };
        cachedThreadPool.execute(bridegroomTask);

        Runnable brideTask = () -> {
            bride.arrive();
            bride.eat();
            bride.leave();
            bride.sleep();
        };
        cachedThreadPool.execute(brideTask);
        cachedThreadPool.shutdown();
    }


    // 定义婚礼的阶段器，第0阶段 人员到达；第 1 阶段 人员吃饭；第2 阶段，离开；第 3 阶段 正经睡觉
    static class MarriagePhaser extends Phaser {

        @Override
        protected boolean onAdvance(int phase, int registeredParties) {
            switch (phase) {
                case 0:
                    System.out.println(registeredParties + " 人到齐了！");
                    System.out.println("------------------------------");
                    return false;
                case 1:
                    System.out.println(registeredParties + " 人吃完了！");
                    System.out.println("------------------------------");
                    return false;
                case 2:
                    System.out.println(registeredParties + " 人离席了！");
                    System.out.println("------------------------------");
                    return false;
                case 3:
                    System.out.println("婚礼结束！新郎新娘 " + registeredParties + " 人洞房！");
                    System.out.println("------------------------------");
                    return true;
                default:
                    return true;
            }
        }
    }

    // 参与婚礼的人员类
    static class Person {

        private String name;
        private MarriagePhaser marriagePhaser;
        // 线程本地随机数工具类
        private ThreadLocalRandom random = ThreadLocalRandom.current();

        // 人员到达
        public void arrive() {
            milliSleep(random.nextInt(1000));
            System.out.println(name + " 到达现场！");
            marriagePhaser.arriveAndAwaitAdvance();
        }

        // 吃饭
        public void eat() {
            milliSleep(random.nextInt(1000));
            System.out.println(name + " 吃完!");
            marriagePhaser.arriveAndAwaitAdvance();
        }

        // 离开
        public void leave() {
            milliSleep(random.nextInt(1000));
            System.out.println(name + " 离开！");
            marriagePhaser.arriveAndAwaitAdvance();
        }

        // 正经睡觉
        private void sleep() {
            if (name.equals("新郎") || name.equals("新娘")) {
                milliSleep(random.nextInt(1000));
                System.out.println(name + " 洞房！");
                marriagePhaser.arriveAndAwaitAdvance();
            } else {
                marriagePhaser.arriveAndDeregister();
            }
        }

        public Person(String name, MarriagePhaser marriagePhaser) {
            this.name = name;
            this.marriagePhaser = marriagePhaser;
        }

    }

    private static void milliSleep(int milli) {
        try {
            TimeUnit.MILLISECONDS.sleep(milli);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
